Preprocesamiento para clustering

Se busca hacer clustering con los atributos numéricos asociados a cada cuenta con el objetivo de observar si existen clases naturales en los datos. Para esto, se crea una nueva tabla con los atributos que serán usados.

Cargar los datos

Se cargan los datos de los 3 millones de tweets, descartando atributos redundantes.

In [1]:
import pandas as pd

columns = [i for i in range(21)]
for i in [20, 19, 16, 15, 12, 0]:
    columns.pop(i)

data = pd.read_csv('../datos/IRAhandle_tweets_1.csv', usecols = columns)
for i in range(2, 14):
    data = data.append(pd.read_csv('../datos/IRAhandle_tweets_{}.csv'.format(i), usecols = columns))
C:\Users\Lenovo\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py:3049: DtypeWarning: Columns (10) have mixed types. Specify dtype option on import or set low_memory=False.
  interactivity=interactivity, compiler=compiler, result=result)

Filtrado de los datos en lenguajes utiles

Algunos lenguajes tienen mayoritariamente tweets mal clasificados, como se detalla en los comentarios del código. Además, entre estos lenguajes que entregan poca confiabilidad, existen datos que han de ser limpiados por otras razones (ej: outliers). Es decir, tras realizar este filtrado, no es necesario limpiar mas los datos.

In [2]:
data_languages = data.loc[(data['language'] == "English") |
                          (data['language'] == "Russian") |
                          (data['language'] == "German" ) |
                          (data['language'] == "Italian") |
                          (data['language'] == "French" ) |
                          (data['language'] == "Japanese")   |
                          (data['language'] == "Portuguese") |
                          (data['language'] == "Macedonian") |
                          (data['language'] == "Serbian")    |
                          (data['language'] == "Ukrainian")  |
                          (data['language'] == "Uzbek")] # No usar booleanos de python
#Legítimos
# Inglés, Ruso, Alemán, Italiano, Francés, Japonés, Portugués
# Macedonio (Ruso?), Serbio (Ruso?), Ucraniano (Ruso?), Uzbek (Ruso?)
# (?) Indefinido(links y hashtags)

#Descartables
# Filipino:   238 tweets, en su mayoría en inglés y sobre Kanye West.
# Estonio:    770 tweets, en varios idiomas.
# Catalán:    589 tweets, en varios idiomas.
# Vietnamita: 982 tweets, en su mayoría en inglés.
# Pushto:     487 tweets, en su mayoría en inglés con algunos en árabe. Parece detectar la palabra sweet.
# Albano:     572 tweets, en su mayoría en inglés. Parece detectar la palabra shit.
# Croata:     572 tweets, en inglés y otros idiomas. Parece detectar la palabra Obama.
# Somalí:     276 tweets, en su mayoría en inglés.
# Persa:     1684 tweets, en varios idiomas. Parece detectar las palabras Kardashian y hashtag.
# Noruego:   2237 tweets, en su mayoría en inglés.
# Rumano:    1629 tweets, en su mayoría en inglés.

#Cuestionables (Contienen una mezcla del idioma predicho y de otros)
# Sueco, Árabe, Holandés, Español

data_languages.shape
Out[2]:
(2901306, 15)

Preprocesado de valores numéricos

Se crea una tabla con el mínimo y máximo de seguidores, número de gente a la que sigue y acciones sobre la cuenta por cada cuenta

In [3]:
ops = ['max', 'min']
account_numbers = data_languages[['author',
                                  'followers',
                                  'following',
                                  'updates',
                                  'publish_date']].groupby('author').agg(ops)
account_numbers.head()
Out[3]:
followers following updates publish_date
max min max min max min max min
author
10_GOP 10465 0 1074 0 352 1 9/9/2017 22:48 10/1/2017 19:58
1488REASONS 6590 6222 6393 1580 2234 1745 9/7/2017 12:06 1/19/2017 13:07
1D_NICOLE_ 53 40 59 48 395 352 9/6/2015 15:33 11/26/2015 22:20
1ERIK_LEE 74 74 239 239 336 330 9/23/2015 9:03 9/23/2015 9:02
1LORENAFAVA1 103 0 417 0 3722 1 5/4/2017 7:57 3/10/2017 0:00

Se añaden columnas con la diferencia de los valores.

In [4]:
for attr in ['followers', 'following', 'updates']:# 'publish_date']:
    account_numbers['{}_max'.format(attr)] = account_numbers[attr]['max']
    account_numbers['{}_min'.format(attr)] = account_numbers[attr]['min']
    account_numbers['diff_{}'.format(attr)] = account_numbers[attr]['max'] - account_numbers[attr]['min']
    del account_numbers[attr]
    
attr = 'publish_date'
col = account_numbers[attr]
frmt = "%m/%d/%Y %H:%M"

account_numbers['diff_publish_date'] = pd.to_datetime(col['max'], format=frmt) - pd.to_datetime(col['min'], format=frmt)
del account_numbers[attr]

Se obtiene la diferencia en dias de tiempo entre los tweets.

In [5]:
import numpy as np

account_numbers['diff_publish_date'] = account_numbers['diff_publish_date']/np.timedelta64(1,'D')
account_numbers['diff_publish_date'] = abs(account_numbers['diff_publish_date'])

Se crean columnas con la diferencia de followers, following y updates por dia.

In [6]:
acc_numbers_2 = account_numbers.loc[account_numbers['diff_publish_date'] != 0]

for attr in ['followers', 'following', 'updates']:
    acc_numbers_2['{}_day'.format(attr)] = acc_numbers_2['diff_{}'.format(attr)] / acc_numbers_2['diff_publish_date']
C:\Users\Lenovo\Anaconda3\lib\site-packages\ipykernel_launcher.py:4: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  after removing the cwd from sys.path.
In [7]:
acc_numbers_2.head()
Out[7]:
followers_max followers_min diff_followers following_max following_min diff_following updates_max updates_min diff_updates diff_publish_date followers_day following_day updates_day
author
10_GOP 10465 0 10465 1074 0 1074 352 1 351 21.881944 478.248175 49.081561 16.040622
1488REASONS 6590 6222 368 6393 1580 4813 2234 1745 489 230.957639 1.593366 20.839319 2.117271
1D_NICOLE_ 53 40 13 59 48 11 395 352 43 81.282639 0.159936 0.135330 0.529018
1ERIK_LEE 74 74 0 239 239 0 336 330 6 0.000694 0.000000 0.000000 8640.000000
1LORENAFAVA1 103 0 103 417 0 417 3722 1 3721 55.331250 1.861516 7.536428 67.249520

Se guarda la tabla

In [9]:
col_names=['followers_max', 'followers_min', 'diff_followers',
           'following_max', 'following_min', 'diff_following',
           'updates_max', 'updates_min', 'diff_updates',
           'diff_publish_date',
           'followers_day', 'following_day', 'updates_day']
acc_numbers_2.to_csv("datos_numericos_cuentas.csv", header=col_names)